﻿using System;
using System.IO;
using System.Net.Sockets;
using System.Workflow.Activities;
using System.Workflow.ComponentModel;
using OscarCloverActivities.Packets;
using OscarCloverActivities.Packets.SignOff;
using OscarCloverActivities.Packets.SignOn;
using OscarCloverActivities.Packets.SnacData;

namespace OscarCloverActivities
{
    public partial class Deserialize : SequenceActivity,IEventActivity
    {
        private BinaryReader _reader;
        private byte _channel;
        private ushort _family;
        private ushort _flags;
        private ushort len;
        private uint _reqId;
        private ushort _subfamily;
        private IActivityEventListener<QueueEventArgs> _parentEventHandler;
        public Deserialize()
        {
            InitializeComponent();
        }

        public NetworkStream NetStream { get; set; }
        public Flap Result { get; set; }
        public UInt16 RecievedSequence { get; set; }

        private void ChannelFound_ExecuteCode(object sender, EventArgs e)
        {
            _channel = _reader.ReadByte();
        }

        private void ConnectionChannelDeserialize_ExecuteCode(object sender, EventArgs e)
        {
            RecievedSequence++;
            Result = new Connect();
            RecievedSequence = (ushort)(256 * _reader.ReadByte() + _reader.ReadByte());
            _reader.ReadBytes(6);
        }

        private void CloseConnectionChannelDeserialize_ExecuteCode(object sender, EventArgs e)
        {
            RecievedSequence++;
            len = (ushort)(_reader.ReadByte() * 256 + _reader.ReadByte());
            var tlvs = new TlvList();
            tlvs.AddRange(GetTlvList(_reader.ReadBytes(len)));
            if (tlvs[0x06] != null)
            {
                Result = new SrvCookie(len, tlvs);
            }
        }

        private void SnacDeserialize_ExecuteCode(object sender, EventArgs e)
        {
            RecievedSequence++;
            len = (ushort)(_reader.ReadByte() * 256 + _reader.ReadByte());
            _family = (ushort)(_reader.ReadByte() * 256 + _reader.ReadByte());
            _subfamily = (ushort)(_reader.ReadByte() * 256 + _reader.ReadByte());
            _flags = (ushort)(_reader.ReadByte() * 256 + _reader.ReadByte());
            _reqId =
                (uint)
                (_reader.ReadByte() * 65535 + _reader.ReadByte() * 4096 + _reader.ReadByte() * 256 + _reader.ReadByte());
        }

        private static TlvList GetTlvList(byte[] data)
        {
            var result = new TlvList();
            for (var i = 0; i < data.Length; )
            {
                var tag = (ushort)(data[i] * 256 + data[i + 1]);
                var len = (ushort)(data[i + 2] * 256 + data[i + 3]);
                var value = new byte[len];
                for (int j = 0; j < len; ++j)
                    value[j] = data[i + 4 + j];
                result.Add(new Tlv(tag, value));
                i = i + 4 + len;
            }
            return result;
        }

        private void ServerReady_ExecuteCode(object sender, EventArgs e)
        {
            Result = new SrvFamilies(len);

            for (var i = 0; i < Result.Len - 10; i++)
            {
                if (i % 2 == 0)
                {
                    _reader.ReadByte();
                }
                else
                {
                    (Result as SrvFamilies).Services.Add(_reader.ReadByte());
                }
            }
        }

        private void RateInfo_ExecudeCode(object sender, EventArgs e)
        {
            _reader.ReadByte();
            Result = new SrvRateLimitInfo(_reader.ReadByte());
            _reader.ReadBytes(len - 12);
        }

        private void JustToRead(object sender, EventArgs e)
        {
            Result = new SrvJust4Read(_family, _subfamily);
            _reader.ReadBytes(len - 10);
        }

        private void FamilyVersionAck_ExecudeCode(object sender, EventArgs e)
        {
            Result = new SrvFamiliesVersions(len);
            for (var i = 0; i < (Result.Len - 10) / 4; i++)
            {
                _reader.ReadByte();
                var curFamily = _reader.ReadByte();
                _reader.ReadByte();
                var curVersion = _reader.ReadByte();
                (Result as SrvFamiliesVersions).Families.Add(curFamily, curVersion);
            }
        }

        private void DropEvent_ExecuteCode(object sender, EventArgs e)
        {
            _parentEventHandler.OnEvent(this,null);
        }

        private void ReaderToStreamSet_ExecuteCode(object sender, EventArgs e)
        {
            _reader = new BinaryReader(NetStream);
        }

        public void Subscribe(ActivityExecutionContext parentContext, IActivityEventListener<QueueEventArgs> parentEventHandler)
        {
            _parentEventHandler = parentEventHandler;
        }

        public void Unsubscribe(ActivityExecutionContext parentContext, IActivityEventListener<QueueEventArgs> parentEventHandler)
        {
            _parentEventHandler = null;
        }

        public IComparable QueueName
        {
            get { return "Deserialize"; }
        }
    }
}